<template>
    <div class="cpc-code-eidt-global">
        <div class="title-box">
            <p class="title">代码编辑器</p>
            <div class="right-menu">
                <n-input-number v-model:value="fontSize" class="input-num" size="tiny" @update:value="setFontSize" />
                <n-select :onUpdate:value="setLanguage" v-model:value="selectLanguage.value" class="selc" size="tiny" :options="selectLanguage.options" />
                <n-select :onUpdate:value="setTheme" v-model:value="selectTheme.value" class="selc" size="tiny" :options="selectTheme.options" />
                <span class="btn" @click="runCode">运行</span>
                <span class="btn" @click="clickSaveHandler">保存</span>
                <span class="btn" @click="clickCloseHandler">关闭</span>
            </div>
        </div>
        <div id="container" class="code-editer-wrap"></div>
    </div>
</template>

<script>
import * as monaco from "monaco-editor";
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker";
import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker";
import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker";
import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker";
// eslint-disable-next-line no-restricted-globals
self.MonacoEnvironment = {
    getWorker(_, label) {
        if (label === "json") {
            // eslint-disable-next-line new-cap
            return new jsonWorker();
        }
        if (label === "css" || label === "scss" || label === "less") {
            // eslint-disable-next-line new-cap
            return new cssWorker();
        }
        if (label === "html" || label === "handlebars" || label === "razor") {
            // eslint-disable-next-line new-cap
            return new htmlWorker();
        }
        if (label === "typescript" || label === "javascript") {
            // eslint-disable-next-line new-cap
            return new tsWorker();
        }
        // eslint-disable-next-line new-cap
        return new editorWorker();
    },
};
let editorInstance = null;
export default {
    props: ["datas", "callBack", "close"],
    data() {
        return {
            fontSize: 20,
            selectLanguage: {
                value: "javascript",
                options: [
                    {
                        label: "javascript",
                        value: "javascript",
                    },
                    {
                        label: "json",
                        value: "json",
                    },
                    {
                        label: "css",
                        value: "css",
                    },
                    {
                        label: "html",
                        value: "html",
                    },
                    {
                        label: "less",
                        value: "less",
                    },
                    {
                        label: "scss",
                        value: "scss",
                    },
                    {
                        label: "typescript",
                        value: "typescript",
                    },
                    {
                        label: "xml",
                        value: "xml",
                    },
                ],
            },
            selectTheme: {
                value: "vs-dark",
                options: [
                    {
                        label: "Visual Studio Dark",
                        value: "vs-dark",
                    },
                    {
                        label: "Visual Studio",
                        value: "vs",
                    },
                    {
                        label: "High Contrast Dark",
                        value: "hc-black",
                    },
                ],
            },
        };
    },
    mounted() {
        this.init(this.datas);
    },
    unmounted() {
        editorInstance = null;
    },
    methods: {
        init({ code, parame }) {
            const preDatas = `const preDatas = ${JSON.stringify(parame.preDatas, null, 2)};\n`;
            const inputInfo = `const inputInfo = ${JSON.stringify(parame.inputInfo, null, 2)};\n`;
            const outputInfos = `const outputInfos = ${JSON.stringify(parame.outputInfos, null, 2)};\n`;
            const value = `${preDatas}${inputInfo}${outputInfos}function run(preDatas, inputInfo , outputInfos){${code}}\nrun(preDatas,outputInfos);`;
            editorInstance = monaco.editor.create(document.getElementById("container"), {
                value,
                language: this.selectLanguage.value,
                theme: this.selectTheme.value,
                scrollBeyondLastLine: false, // 取消代码后面一大段空白
                fontSize: this.fontSize,
                readOnly: this.datas.readOnly,
            });
        },
        runCode() {
            try {
                // @ts-ignore
                const fun = new Function("preData", editorInstance.getValue());
                fun();
                window.$message.success("代码通过!!");
            } catch (e) {
                console.error(e);
                window.$message.error("代码运行失败,详细请看控制台!");
            }
        },
        setTheme() {
            monaco.editor.setTheme(this.selectTheme.value);
        },
        setLanguage() {
            monaco.editor.setModelLanguage(editorInstance.getModel(), this.selectLanguage.value);
        },
        setFontSize() {
            editorInstance.updateOptions({ fontSize: this.fontSize });
        },
        clickCloseHandler() {
            this.close();
        },
        clickSaveHandler() {
            const regexp = /\s*(?:(async)\s+)?function\s+run\s*\((\s*preDatas\s*,\s*outputInfos\s*)\)\s*?\{\s*([\s\S]*)\s*\}\s*/;
            const value = editorInstance.getValue();
            const result = value.match(regexp);
            if (!result || result.length < 3) {
                window.$message.error("function run(preDatas, outputInfos){}结构体是固定的不能修改!");
                return;
            }
            this.callBack(result[3]);
        },
    },
};
</script>

<style scoped lang="scss">
.cpc-code-eidt-global {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: #000;
    z-index: 10;

    .title-box {
        height: 40px;
        line-height: 40px;

        .title {
            margin-left: 30px;
            color: #fff;
        }

        .right-menu {
            position: absolute;
            top: 0;
            right: 30px;
            display: flex;
            color: #fff;
            .input-num {
                width: 80px;
                margin: 0 10px;
                top: -8px;
            }
            .selc {
                width: 150px;
                margin: 0 10px;
                top: -8px;
            }

            .btn {
                cursor: pointer;
                margin: 0 10px;

                &:hover {
                    color: #0e7a0d;
                }
            }
        }
    }

    .code-editer-wrap {
        border: 1px solid #ccc;
        height: calc(100% - 40px);
        width: 100%;
    }
}
</style>
